Inversion of Control implemented using Dependency Injection, implemented by: - setter method taking a resource - constructor method taking a resource - interface injection (implement an interface that takes a set of resources and uses the required ones) setter and constructor are more widely supported. spring core implements a container BeanFactory spring context implements a more advanced container ApplicationContext with i18N and other features spring also has MVC, portlet MVC, testing, and integration with other ORM and web frameworks spring projects include: - spring IDE - plugin for eclipse - spring security - authentication, authorization, access control framework - spring web flow - model user interactions within a web app as flows - spring web services - contract first and document driven web services - spring rich client - rich GUI applications developed with spring - spring batch - batch processing - spring modules - misc tools? - spring dynamic modules - supports creating spring apps to run on osgi platform which allows dynamic installation, updating, loading, unloading - spring integration - support enterprise integration with external systems - spring ldap - spring javaconfig - java based alternative to configuring components - spring beandoc - generate documentation and diagrams based on bean config file - spring .net - .net version of spring Installing Spring IDE Tool: http://blog.springsource.com/2009/06/24/installing-sts-into-eclipse-35/ include these jars in classpath: - dist/spring.jar (or dist/modules/whateveryouneed) - lib/jakarta-commons/commons-logging.jar --------- Guide Based on http://static.springsource.org/docs/Spring-MVC-step-by-step/ Create regular Web Project Add the spring dispatcher to web.xml: springapp org.springframework.web.servlet.DispatcherServlet 1 springapp *.htm Create a file for spring MVC with pattern -servlet.xml to specify which url is handled by which controller: Copy dist/spring.jar, dist/modules/spring-webmvc.jar, lib/jakarta-commons/commons-logging.jar to WEB-INF/lib Create controller classes specified in *-servlet.xml: package springapp.web; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.IOException; public class HelloController implements Controller { protected final Log logger = LogFactory.getLog(getClass()); public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.info("Returning hello view"); return new ModelAndView("hello.jsp"); } } Controllers handle the request and return a ModelAndView. The model is resolved via a ViewResolver - in this case a default one is used. Create the view hello.jsp: Hello :: Spring Application

Hello - Spring Application

Greetings.

Write a test for the controller, also need to add copy junit 3.8.2 or 4.4 to web-inf/lib: package springapp.tests; import org.springframework.web.servlet.ModelAndView; import springapp.web.HelloController; import junit.framework.TestCase; public class HelloControllerTests extends TestCase { public void testHandleRequestView() throws Exception{ HelloController controller = new HelloController(); ModelAndView modelAndView = controller.handleRequest(null, null); assertEquals("hello.jsp", modelAndView.getViewName()); } } To run a JUnit test: Window > Open View > JUnit right-click on a class that is subclass of TestCase, Run > JUnit Will run all methods in class that are test* If there is a method called setUp, it is run before the tests (can be used to get data etc) JSTL & JSP header Copy lib/j2ee/jstl.jar (JSP Standard Tag Library) and lib/jakarta-taglibs/standard.jar to WEB-INF/lib Create include.jsp in WEB-INF/jsp: <%@ page session="false"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> JSTL Core: <%@ include file="/WEB-INF/jsp/include.jsp" %> $

JSTL Formatter - formatting and internationalisation: - page = this page - request = all pages in this request - session = all requests in this session - application = all requests for all users - scope is optional, value can indicate country like en_US apply only to this block -- formatted date is put in var if var specified, else printed fmt:parseDate and parseNumber can be used to read a string into a number/date variable messages..params.. prefix is applied to key automatically http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/index.html Decoupling the view from the controller: In -servlet.xml, add: Now any view string returned will automatically have /WEB-INF/jsp prepended and .jsp appended. This is done by spring and uses InternalResourceViewResolver. JstlView allows us to support internationalization and use JSTL. Typical design involves writing a class to hold data, a class to manage the data and test classes. Managing classes are defined by an interface. Controller class has a setter (IoC) to receive the manager object thus avoiding dependency on any manager implementation and only depending on the interface. Setting values in objects and passing them through the IoC setter: In -servlet.xml: ... Setting a source for messages: Create messages.properties in WEB-INF/classes which is read when fmt:message key is called title=SpringApp heading=Hello :: SpringApp greeting=Greetings, it is now Spring's form tag library: copy dist/resources/spring-form.tld to WEB-INF/tld Create taglib entry in web.xml: /spring /WEB-INF/tld/spring-form.tld in JSP file: <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> Create a bean with same name as commandName (PriceIncrease) with setters for all input.. i.e. get/setPercentage Create a validator class with name PriceIncreaseValidator: import org.springframework.validation.Validator; import org.springframework.validation.Errors; public class PriceIncreaseValidator implements Validator { public boolean supports(Class clazz) { return PriceIncrease.class.equals(clazz); } public void validate(Object obj, Errors errors) { ... errors.rejectValue("percentage", "error.not-specified", null, "Value required."); errors.rejectValue("percentage", "error.too-high/low", new Object[] {new Integer(maxPercentage)}, "Value too high/low."); } } Add a form controller: Add an entry in *-servlet.xml to define the new form and controller: - commandClass and validator are injected - formView (show form) and successView (successful process) - successView can be a regular view reference forwarded to JSP (refresh causes resubmit) or redirect The form controller class: flow: http://static.springsource.org/spring/docs/2.0.8/api/org/springframework/web/servlet/mvc/AbstractFormController.html import org.springframework.web.servlet.mvc.SimpleFormController; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; public ModelAndView onSubmit(Object command) throws ServletException { PriceIncrease formObj = (PriceIncrease) command; int percent = formObj.getPercentage(); productManager.increasePrice(increase); return new ModelAndView(new RedirectView(getSuccessView())); // redirect to success view } protected Object formBackingObject(HttpServletRequest request) throws ServletException { // return a preconfigured PriceIncrease object (which may be reconfigured later) // this will set form defaults } public void setProductManager(ProductManager productManager) ... public ProductManager getProductManager()... Setting default error messages: required=Entry required. typeMismatch=Invalid data. typeMismatch.percentage=That is not a number!!! Using JDBC with Spring: Create an interface (good practise but not required) Implement the interface with Spring's JDBC abstraction framework - which handles opening/closing connections and statements: import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.simple.ParameterizedRowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport; // SimpleJdbcDaoSupport provides convenient access to an already configured SimpleJdbcTemplate public class JdbcProductDao extends SimpleJdbcDaoSupport implements ProductDao { ... // selecting data: List products = getSimpleJdbcTemplate().query( "select id, description, price from products", new ProductMapper()); // updating data: int count = getSimpleJdbcTemplate().update( "update products set description = :description, price = :price where id = :id", new MapSqlParameterSource().addValue("description", prod.getDescription()) .addValue("price", prod.getPrice()) .addValue("id", prod.getId())); // resultset to product mapper: private static class ProductMapper implements ParameterizedRowMapper { public Product mapRow(ResultSet rs, int rowNum) throws SQLException { Product prod = new Product(); prod.setId(rs.getInt("id")); prod.setDescription(rs.getString("description")); prod.setPrice(new Double(rs.getDouble("price"))); return prod; } } } Spring test framework Copy spring-test.jar from dist/modules to WEB-INF/lib for datasource testing create a new class extending AbstractTransactionalDataSourceSpringContextTests - is transactional - any changes we made are rolled back at the end - we get dependency injection (configured in xml file returned by getConfigLocations method) - onSetUpInTransaction lets us load test data, etc - deleteFromTables(String[] tables) can be called to empty existing tables - executeSqlScript("filename", true) can be called to execute a script (to load data etc) in xml file returned by getConfigLocations: classpath:jdbc.properties and jdbc.properties in WEB-INF/classes: jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost jdbc.username=root jdbc.password=a1b3c2a Using JDBC classes we created: To inject a DAO class, create WEB-INF/applicationContext.xml, which is loaded when you add this to web.xml: org.springframework.web.context.ContextLoaderListener productManager = new SimpleProductManager(); productManager.setProductDao(new InMemoryProductDao(products)); AspectJ: - Basic idea of AOP is to consolidate all cross-cutting code (debugging, logging, transactions, security, ...) that are normally spread throughout into one location for easier maintenance. - Join points are points where aspects are applied to code. In AspectJ they are specified by "pointcuts" which are method signatures.. examples: - "execution(* set*(*))" matches method execution join point if the method name starts with set and has 1 arg of any type - "this(Point)" - matches when current object is an instance of class Point - "within(com.company.*)" - matches any join point in any type in the com.company package - Pointcuts can be named for reuse: pointcut set() : execution(* set*(*)) && this(Point) and later.. after() : set() { Display.update(); } above code runs Display.update() after the join point Adding transaction and connection pool configuration to app context: Copy aspectjweaver.jar from lib/aspectj and commons-dbcp.jar and commons-pool.jar from lib/jakarta-commons to WEB-INF/lib applicationContext.xml: "execution(* *..ProductManager.*(..))" matches any method called on the ProductManager interface Also in applicationContext.xml, set up the connection pool: classpath:jdbc.properties